package jcurses.widgets;

import java.util.Vector;

import jcurses.event.ValueChangedEvent;
import jcurses.event.ValueChangedListener;
import jcurses.event.ValueChangedListenerManager;
import jcurses.system.CharColor;
import jcurses.system.InputChar;
import jcurses.system.Toolkit;
import jcurses.util.Rectangle;

/**
 * This class implements a popup list. Such list has always one of the items
 * selected and gives the possibility to change this selection ( througth an
 * popup menu that is shown, if the user typed 'enter')
 * 
 */
public class PopUpList extends Widget implements IFocusable {

	private int _selectedIndex = -1;
	Vector<String> _items = new Vector<String>();

	private FocusData focus = new FocusData();

	private ValueChangedListenerManager _listenerManager = new ValueChangedListenerManager();

	private static CharColor __popUpDefaultColors = new CharColor(
			CharColor.WHITE, CharColor.BLACK);

	private static CharColor __focusedPopUpDefaultColors = new CharColor(
			CharColor.BLUE, CharColor.WHITE, CharColor.REVERSE);

	private CharColor _focusedPopUpColors = getFocusedPopUpDefaultColors();
	private static InputChar __changeValueChar = new InputChar('\n');

	public PopUpList() {
		super();
	}

	/**
	 * Adds an item at the specified position
	 * 
	 * @param item
	 *            the item to add
	 * @param pos
	 *            position
	 */
	public void add(int pos, String item) {
		_items.add(pos, item);
	}

	/**
	 * Adds an item
	 * 
	 * @param item
	 *            the item to add
	 */
	public void add(String item) {
		_items.add(item);
	}

	/**
	 * Adds a listener to register selected value changes
	 * 
	 */
	public void addListener(ValueChangedListener listener) {
		_listenerManager.addListener(listener);
	}

	/**
	 * Clears the item list
	 */
	public void clear() {
		_items.clear();
	}

	public CharColor getDefaultColors() {
		return __popUpDefaultColors;
	}

	@Override
	public void getFocus() {
		this.focus.focus = true;
		paint();
	}

	/**
	 * @raturn colors used to paint the widget, if it has focus
	 * 
	 */
	public CharColor getFocusedPopUpColors() {
		return _focusedPopUpColors;
	}

	/**
	 * Returns the currently selected index
	 * 
	 * @return currently selected index
	 */
	public int getSelectedIndex() {
		if (_selectedIndex != -1) {
			return _selectedIndex;
		} else {
			if (_items.size() > 0) {
				return 0;
			} else {
				return -1;
			}
		}
	}

	/**
	 * Returns the currently selected item
	 * 
	 * @return currently selected item
	 */
	public String getSelectedItem() {
		if (getSelectedIndex() >= 0) {
			return (String) _items.elementAt(getSelectedIndex());
		} else {
			return null;
		}
	}

	@Override
	public boolean hasFocus() {
		return this.focus.focus;
	}

	@Override
	public boolean isFocusable() {
		return this.focus.focusable;
	}

	@Override
	public void lostFocus() {
		this.focus.focus = false;
		paint();
	}

	/**
	 * Removes the item at the specified position
	 * 
	 * @param pos
	 *            position
	 */
	public void remove(int pos) {
		_items.remove(pos);
	}

	/**
	 * Removes the first ocuurence of the specified item
	 * 
	 * @param item
	 *            item to be removed
	 * 
	 */
	public void remove(String item) {
		_items.remove(item);
	}

	/**
	 * Removes a listener
	 * 
	 */
	public void removeListener(ValueChangedListener listener) {
		_listenerManager.removeListener(listener);
	}

	@Override
	public void setFocus(boolean value) {
		if (value) {
			getFocus();
		} else {
			lostFocus();
		}
	}

	@Override
	public void setFocusable(boolean focusable) {
		this.focus.focusable = focusable;
	}

	/**
	 * Sets colors used to paint the widget, if it has focus
	 * 
	 * @param colors
	 *            colors used to paint the widget, if it has focus
	 */
	public void setFocusedPopUpColors(CharColor colors) {
		_focusedPopUpColors = colors;
	}

	private CharColor getFocusedPopUpDefaultColors() {
		return __focusedPopUpDefaultColors;
	}

	private int getMaxLength() {
		int result = 0;
		for (int i = 0; i < _items.size(); i++) {
			String item = (String) _items.elementAt(i);
			if (item.length() > result) {
				result = item.length();
			}
		}

		return result;
	}

	private String getText() {
		String result = null;
		int length = getSize().getWidth() - 2;
		String item = (getSelectedItem() == null) ? "" : getSelectedItem();
		if (item.length() > length) {
			result = item.substring(0, length);
		} else {
			StringBuffer buf = new StringBuffer();
			buf.append(item);
			for (int i = 0; i < (length - item.length()); i++) {
				buf.append(' ');
			}
			result = buf.toString();
		}

		return result;
	}

	protected void doPaint() {
		Rectangle rect = (Rectangle) getSize().clone();
		rect.setLocation(getAbsoluteX(), getAbsoluteY());
		String text = "[" + getText() + "]";
		CharColor colors = hasFocus() ? getFocusedPopUpColors() : getColors();
		Toolkit.printString(text, rect, colors);
	}

	protected void doRepaint() {
		doPaint();
	}

	protected Rectangle getPreferredSize() {
		return new Rectangle(2 + getMaxLength(), 1);
	}

	protected boolean handleInput(InputChar ch) {
		if (ch.equals(__changeValueChar)) {
			if (_items.size() > 2) {
				PopUpMenu menu = new PopUpMenu(getAbsoluteX(), getAbsoluteY(),
						null);
				for (int i = 0; i < _items.size(); i++) {
					menu.add((String) _items.elementAt(i));
				}
				menu.show();
				if ((menu.getSelectedIndex() != -1)
						&& (menu.getSelectedIndex() != getSelectedIndex())) {
					_selectedIndex = menu.getSelectedIndex();
					paint();
					_listenerManager.handleEvent(new ValueChangedEvent(this));

				}
			}

			return true;
		}

		return false;
	}

}
